/**
 * <pre>
 * @(#)View.java 1.00 2009-11-4
 * 
 * Copyright (c) 1998, 2009 Regular Individual. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Contributor(s):
 *     Haixu Huang
 * </pre>
 **/
package cn.sh.huang.chart.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;

import cn.sh.huang.chart.ext.MouseEventAdapter;
import cn.sh.huang.chart.view.container.Container;

/**
 * <pre>
 * View ...
 * 
 * @version 1.0
 * </pre>
 */
public abstract class View extends MouseEventAdapter implements AbstractView
{
    protected static final int MINIMUM_VIEW_WIDTH = 32;
    private static final Color DEFAULT_BGCOLOR = new Color(0xF0, 0xF0, 0xF0);
    protected static final Graphics2D DEFAULT_CANVAS =
        (Graphics2D) new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();

    private Container container = null;
    private Color bgColor = DEFAULT_BGCOLOR;
    private Point gridAnchor = new Point(); // Anchor position(relative to container)
    private Dimension viewSize = new Dimension();

    /**
     * <code>        viewRect.y
     *  +------------------+--------------------+
     *  |              ^   |                    |
     *  |  gridAnchor  v   |                    |
     *  |<-          ->+---+--------------------+-+
     *  |              |   v                    | |
     * viewRect.x------+-->+------------------+ | |
     *  |              |   |                  | | |
     *  |              |   |     viewRect     | | |
     *  |  container   |   |                  | | |
     *  |              |   +------------------+ | |
     *  +--------------+------------------------+ |
     *                 |                     view |
     *                 +--------------------------+
     * </code>
     */

    public void dispose()
    {
        container.removeMouseEventListener(this);
        container = null;
    }

    final public Color getBgColor()
    {
        return bgColor;
    }

    final public Container getViewContainer()
    {
        return container;
    }

    final public void processMouseEvent(MouseEvent e)
    {
        int id = e.getID();
        switch (id) {
            case MouseEvent.MOUSE_PRESSED:
                mousePressed(e);
                break;
            case MouseEvent.MOUSE_RELEASED:
                mouseReleased(e);
                break;
            case MouseEvent.MOUSE_CLICKED:
                mouseClicked(e);
                break;
            case MouseEvent.MOUSE_EXITED:
                mouseExited(e);
                break;
            case MouseEvent.MOUSE_ENTERED:
                mouseEntered(e);
                break;
            case MouseEvent.MOUSE_MOVED:
                mouseMoved(e);
                break;
            case MouseEvent.MOUSE_DRAGGED:
                mouseDragged(e);
                break;
            case MouseEvent.MOUSE_WHEEL:
                mouseWheelMoved((MouseWheelEvent) e);
        }

    }

    final public void repaint()
    {
        if (container != null) {
            container.repaint();
        }
    }

    final public void setBgColor(Color bgColor)
    {
        this.bgColor = bgColor;
    }

    final public void setViewContainer(Container container)
    {
        if (this.container != null) {
            throw new IllegalArgumentException("!ERROR! View has already been nested in another Container.");
        }
        container.addMouseEventListener(this);
        this.container = container;
    }

    public void setViewSize(final int width, final int height)
    {
        if (width < 0 || height < 0) {
            return;
        }
        viewSize.setSize(width, height);
        update();
    }

    final public Dimension getViewSize()
    {
        return (Dimension) viewSize.clone();
    }

    public void setGridAnchor(final int x, final int y)
    {
        gridAnchor.setLocation(x, y);
    }

    public Point getViewShift()
    {
        Point shift = container.getViewShift();
        shift.translate(-gridAnchor.x, -gridAnchor.y);
        Point gridLocation = container.getGridRect(this).getLocation();
        shift.translate(gridLocation.x, gridLocation.y);
        return shift;
    }

    public Point getGridAnchor()
    {
        return (Point) gridAnchor.clone();
    }

    public Point getViewAnchor()
    {
        Rectangle gridRect = getGridRect();
        Point gridAnchor = getGridAnchor(); // Accumulated shift of container
        gridRect.translate(gridAnchor.x, gridAnchor.y); // Absolute position of view area

        Point viewAnchor = container.getViewAnchor();
        Point gridCorner = container.getGridRect(this).getLocation();
        return new Point(viewAnchor.x + gridCorner.x - gridAnchor.x, viewAnchor.y + gridCorner.y - gridAnchor.y);
    }

    public Rectangle getGridRect()
    {
        return container.getGridRect(this);
    }

    public Rectangle getViewRect()
    {
        return container.getViewRect(this);
    }

    final public void update()
    {
        if (viewSize.width != 0 && viewSize.height != 0) {
            doUpdate();
            repaint();
        }
    }

    protected void doUpdate()
    {
    }
}
